package com.wan.paypal.v2;

import com.paypal.http.HttpResponse;
import com.paypal.http.serializer.Json;
import com.paypal.orders.*;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

@Controller
@RequestMapping("/v2")
public class PayPalCheckoutController {

    private ConcurrentHashMap<String, String> orderPaymMap = new ConcurrentHashMap();// orderNo与orderId的对应关系
    private Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    private PayPalCheckoutService payPalCheckoutService;
    @Autowired
    private PayPalConfig config;

    /**
     * 首页
     */
    @RequestMapping(method = RequestMethod.GET)
    public String index() {
        return "index";
    }

    /**
     * 1、创建订单请求
     */
    @RequestMapping(method = RequestMethod.POST, value = "pay")
    public String pay() {
        log.info("创建订单=========================================================================================");
        String local_order_no = "202011161003" + UUID.randomUUID();
        OrdersCreateRequest request = new OrdersCreateRequest();
        request.header("prefer", "return=representation");
        request.requestBody(payPalCheckoutService.buildCreateRequestBody(local_order_no));
        HttpResponse<Order> response = null;
        try {
            response = config.client().execute(request);
        } catch (IOException e1) {
            try {
                log.error("第1次调用paypal订单创建失败");
                response = config.client().execute(request);
            } catch (Exception e) {
                try {
                    log.error("第2次调用paypal订单创建失败");
                    response = config.client().execute(request);
                } catch (Exception e2) {
                    log.error("第3次调用paypal订单创建失败，失败原因：{}", e2.getMessage());
                }
            }
        }
        String approve = "";
        if (response.statusCode() == 201) {
            log.info("Status Code = {}, Status = {}, OrderID = {}, Intent = {}", response.statusCode(), response.result().status(), response.result().id(), response.result().checkoutPaymentIntent());
            for (LinkDescription link : response.result().links()) {
                log.info("Links-{}: {}    \tCall Type: {}", link.rel(), link.href(), link.method());
                if (link.rel().equals("approve")) {
                    // 客户付款登陆地址【判断币种CNY无法交易】
                    //  String paymentId = payment.getId(); orderPaymMap.put(orderId, paymentId);// 保存本地OrderId和paymentId对应关系
                    approve = link.href();
//                    log.info("创建支付订单返回paymentId : " + paymentId);
//                    log.info("支付订单状态state : " + payment.getState());
//                    log.info("支付订单创建时间create_time : " + payment.getCreateTime());
                    log.info("=========================================================================================");
                    return "redirect:" + approve;
                }
            }
        }
        log.info("=========================================================================================");
        return "redirect:/";
    }

    /**
     * 2、失败回调
     *   触发回调情景：
     *     1、用户在支付页面点击取消支付
     *     2、用户支付成功后点击网页回退，再点击返回商家按钮触发
     *   判断是否用户主动取消付款逻辑：
     *     1、设置回调地址的时候拼接本地订单ID：?orderId=XXXX
     *     2、然后根据orderId查询paymentId，继而调用sdk查询订单支付状态
     *      * http://localhost:8080/pay/cancel?orderId=2020110200001&token=EC-70674489LL9806126
     */
    @RequestMapping(method = RequestMethod.GET, value = "pay/cancel")
    public String cancelPay(@RequestParam("token") String orderNo, @RequestParam String local_order_no) {
        try {
            log.info("失败回调=========================================================================================");
            log.info("交易取消回调：支付订单状态：");
            HttpResponse<Order> response = payPalCheckoutService.getOrdersInfo(orderNo);
            log.info("Status Code: " + response.statusCode());
            log.info("Status: " + response.result().status());
            log.info("Order id: " + response.result().id());
            log.info("local_order_no: " + local_order_no);
            log.info("=========================================================================================");
            if ("COMPLETED".equals(response.result().status())) {
                return "success";
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return "cancel";
    }

    /**
     * 3、用户授权成功回调
     *      执行支付 + PDT同步通知支付结果
     */
    @RequestMapping(method = RequestMethod.GET, value = "pay/success")
    public String successPay(@RequestParam("PayerID") String payerId, @RequestParam("token") String orderNo) {
        log.info("成功回调=========================================================================================");
        try {
            // 执行支付
            HttpResponse<Order> response = payPalCheckoutService.authorizeOrder(orderNo);
            if ("COMPLETED".equals(response.result().status())) {
                log.info("=========================================================================================");
                return "success";
            }
        } catch (Exception e) {
            // 如果同步通知返回异常，可根据paymentId 来查询刷新订单状态
            // 同时IPN异步通知也可以更新订单状态
            log.error(e.getMessage());
        }
        log.info("=========================================================================================");
        return "redirect:/";
    }

    /**
     * 4、发起退款
     */
    @RequestMapping(method = RequestMethod.GET, value = "pay/refund")
    @ResponseBody
    public String refund(@RequestParam("orderNo") String orderNo) {
        log.info("发起退款=========================================================================================");
        try {
            HttpResponse<com.paypal.payments.Refund> response = payPalCheckoutService.refundOrder(orderNo);
            String json = new JSONObject(new Json().serialize(response.result())).toString(4);
            return json;
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("=========================================================================================");
        return "";
    }


    /**
     * 5、IPN异步通知
     *   触发情景：
     *      1、买家支付成功
     *      2、卖家确认收取授权或订单款项
     *      3、卖家发放退款
     */
    @ResponseBody
    @PostMapping(value = "/paypal/ipn/back")
    public String callback(HttpServletRequest request) {
        log.info("IPN异步通知=========================================================================================");
        Map parameterMap = RequestToMapUtil.getParameterMap(request);
        String callback = payPalCheckoutService.callback(parameterMap);
        log.info("auth_status：" + parameterMap.get("auth_status"));
        log.info("pending_reason：" + parameterMap.get("pending_reason"));
        log.info("payment_status：" + parameterMap.get("payment_status"));
        log.info("=========================================================================================");
        return callback;
    }

//    /**
//     * IPN异步通知
//     *   触发情景：
//     *      1、买家支付成功
//     *      2、卖家确认收取授权或订单款项
//     *      3、卖家发放退款
//     */
//    @RequestMapping(method = RequestMethod.POST, value = "/notificationIPN", produces = "application/json;charset=utf-8")
//    public void receivePaypalStatus(HttpServletRequest request, HttpServletResponse response) throws Exception {
//        log.info("=========================================================================================");
//        log.info("IPN通知：异步回调");
//        PrintWriter out = response.getWriter();
//        try {
//            Enumeration<String> en = request.getParameterNames();
//            /**
//             * 修改订单状态
//             *      保存失败则不验签，继续接受paypal异步回调直至保存成功【或者用MQ】
//             */
//            String paymentStatus = request.getParameter("payment_status").toUpperCase();  // 交易状态
//            String paymentDate = request.getParameter("payment_date");      // 交易时间
//            String custom = request.getParameter("custom");                 // 本地系统订单ID
//            String auth_id = request.getParameter("auth_id");               // transactionId
//            String txnId = request.getParameter("txn_id");                  // 当前回调数据id【具体逻辑查看 .md文档】
//            String parentTxnId = request.getParameter("parent_txn_id");     // 父id
//            String receiverEmail = request.getParameter("receiver_email");  // 收款人email
//            String receiverId = request.getParameter("receiver_id");        // 收款人id
//            String payerEmail = request.getParameter("payer_email");        // 付款人email
//            String payerId = request.getParameter("payer_id");              // 付款人id
//            String mcGross = request.getParameter("mc_gross");              // 交易金额
//            String item_name = request.getParameter("item_name");
//            log.info("paymentStatus = " + paymentStatus);
//            log.info("txnId = " + txnId);
//            log.info("parentTxnId = " + parentTxnId);
//            log.info("authId（transactionId）= " + auth_id);
//            log.info("custom（orderId）= " + custom);
//            log.info("request item_name= " + item_name);
//            //log.info("request item_name= " + new String(request.getParameter("item_name").getBytes("ISO-8859-1"), "UTF-8"));
//            //log.info("item_name= " + new String(item_name.getBytes("ISO-8859-1"), "UTF-8"));
//            //log.info("URLDecoder item_name= " + new String(URLDecoder.decode(request.getParameter("item_name"), "ISO-8859-1")));
//            /**
//             * 验证
//             *   作用：
//             *     订单状态修改成功，告诉paypal停止回调
//             *   实现：
//             *     在原参数的基础上加cmd=_notify-validate，然后对https://www.sandbox.paypal.com/cgi-bin/webscr发起POST验证请求
//             */
//            String str = "cmd=_notify-validate";
//            while (en.hasMoreElements()) {
//                String paramName = en.nextElement();
//                String paramValue = request.getParameter(paramName);
//                //此处的编码一定要和自己的网站编码一致，不然会出现乱码，paypal回复的通知为"INVALID"
//                str = str + "&" + paramName + "=" + URLEncoder.encode(paramValue, "utf-8");
//            }
//            log.info("paypal传递过来的交易信息:" + str);// 建议在此将接受到的信息 str 记录到日志文件中以确认是否收到 IPN 信息
//            URL url = new URL(paypalConfig.getWebscr());
//            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//            connection.setRequestMethod("POST");
//            connection.setDoOutput(true);
//            connection.setDoInput(true);
//            connection.setUseCaches(false);
//            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");//设置 HTTP 的头信息
//            PrintWriter pw = new PrintWriter(connection.getOutputStream());
//            pw.println(str);
//            pw.close();
//            /**
//             * 回复
//             *    接受PayPal对验证的回复信息
//             */
//            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
//            String resp = in.readLine();
//            in.close();
//            resp = StringUtils.isEmpty(resp) ? "0" : resp;
//            log.info("resp = " + resp);
//            /**
//             * 验证返回状态
//             */
//            if (PaypalConfig.PAYMENT_IPN_VERIFIED.equalsIgnoreCase(resp)) {
//                /**
//                 * 修改订单状态
//                 *      根据订单状态paymentStatus确定当前回调的类型
//                 */
//                switch (paymentStatus) {
//                    case PaypalConfig.PAYMENT_STATUS_PENDING:
//                        // 商家待领取状态
//                        break;
//                    case PaypalConfig.PAYMENT_STATUS_VOIDED:
//                        // 商家作废（30天以内，且必须是授权付款类型 或 订单付款类型），款项原路返回买家
//                        break;
//                    case PaypalConfig.PAYMENT_STATUS_COMPLETED:
//                        // 商家领取
//                        String captureId = txnId;   // 实际领取对象ID【授权付款 和 订单付款需要商家领取】
//                        break;
//                    case PaypalConfig.PAYMENT_STATUS_REFUNDED:
//                        // 商家退款，需扣除费用
//                        String refundId = txnId;
//                        String captureId2 = parentTxnId;
//                        break;
//                }
//            } else if (PaypalConfig.PAYMENT_IPN_INVALID.equalsIgnoreCase(resp)) {
//                // 非法信息，可以将此记录到您的日志文件中以备调查
//                log.error("IPN通知返回状态非法，请联系管理员，请求参数：" + str);
//                log.error("Class: " + this.getClass().getName() + " method: " + Thread.currentThread().getStackTrace()[1].getMethodName());
//                out.println("confirmError");
//            } else {// 处理其他错误
//                log.error("IPN通知返回状态非法，请联系管理员，请求参数：" + str);
//                log.error("Class: " + this.getClass().getName() + " method: " + Thread.currentThread().getStackTrace()[1].getMethodName());
//                out.println("confirmError");
//            }
//        } catch (Exception e) {
//            log.error("IPN通知发生IO异常" + e.getMessage());
//            log.error("Class: " + this.getClass().getName() + " method: " + Thread.currentThread().getStackTrace()[1].getMethodName());
//            out.println("confirmError");
//            e.printStackTrace();
//        }
//        out.flush();
//        out.close();
//        log.info("=========================================================================================");
//    }

    /**
     * 5、查询支付单接口：
     */
    @RequestMapping(method = RequestMethod.GET, value = "orderInfo")
    @ResponseBody
    public String selectOrderState(@RequestParam("orderNo") String orderNo) {
        log.info("查询支付单接口=========================================================================================");

        String state = "异常";
        try {
            HttpResponse<Order> response = payPalCheckoutService.getOrdersInfo(orderNo);

            System.out.println("查询支付单接口: ");
            System.out.println("Status Code: " + response.statusCode());
            System.out.println("Status: " + response.result().status());
            System.out.println("Order id: " + response.result().id());
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("=========================================================================================");
        return state;
    }

    /**
     * 6、查询授权订单接口：
     */
    @RequestMapping(method = RequestMethod.GET, value = "transactionInfo")
    @ResponseBody
    public String selectTransactionState(@RequestParam("transactionNo") String transactionNo) {
        log.info("查询授权订单接口=========================================================================================");

        String state = "异常";
        try {
            state = payPalCheckoutService.getAuthorizeInfo(transactionNo);
            log.info("查询授权订单接口 state:" + state);
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("=========================================================================================");
        return state;
    }
}